<?php
/**
 * Created by PhpStorm.
 * User: guokunsheng
 * Date: 2018/12/4
 * Time: 15:22
 */

namespace app\common\model;

use app\common\lib\exception\ApiException;
use think\Cache;

/**
 * 二十四节气数据
 * Class SolarTerms
 * @package app\common\model
 */
class SolarTerms extends Base
{
    protected $table = 'wechat_backup_07_18_14_43_00.app_solar_terms';

    const MINYEAR = 1800;// 数据库中存储的最小年份
    const MAXYEAR = 2128;// 数据库中存储的最大年份
    const CACHE_KEY = 'solar_terms';
    const CACHE_TIME = 2592000;

    /**
     * 获取最近的节令时间
     * @param array $map
     * @return int
     * @throws ApiException
     */
    public function getTremTime($map = [])
    {
        $data = false;
        // 获取二十四节气表
        $datas = $this->getTermsByDate($map['time']);

        if (!empty($datas))
        {
            $total = count($datas);

            $yearDiff = (int)(date('Y', $map['time'])) - (int)(date('Y', $datas[0]['time']));
            $monthDiff = (int)(date('n', $map['time'])) - (int)(date('n', $datas[0]['time']));
            /**
             * 计算循环起点（倒序比较）
             * 一年24个节气
             * 一个月2个节气
             */
            $diff = $yearDiff * 24 + $monthDiff * 2;

            if (strtolower($map['sort']) === 'asc')
            {
                // 阳男 || 阴女  顺推 六十甲子顺行 下一个节令时间 （节令黄经度数 为15°的奇数倍数）
                for ($i = $diff - 1; $i < $total; $i++)
                {
                    if (!isset($datas[$i]) || $datas[$i]['deg'] % 2 !== 1)
                    {
                        continue;
                    }
                    if ($datas[$i]['time'] > $map['time'])
                    {
                        $data = $datas[$i]['time'];
                        break;
                    }
                }
            } else
            {
                // 阴男 || 阳女 逆推 六十甲子逆行  上一个节令时间 （节令黄经度数 为15°的奇数倍数）
                for ($i = $diff + 1; $i >= 0; $i--)
                {
                    if (!isset($datas[$i]) || $datas[$i]['deg'] % 2 !== 1)
                    {
                        continue;
                    }
                    if ($datas[$i]['time'] < $map['time'])
                    {
                        $data = $datas[$i]['time'];
                        break;
                    }
                }
            }
        }
        if ($data === false)
        {
            \think\Log::write('请及时补充二十四节气时间表：' . $map['time'], 'error', true);
            throw new ApiException('节令时间查询失败');
        }
        return $data;
    }

    /**
     * 获取当前时间前后总共三年的二十四节气时间 并缓存
     * 按时间正序排序
     * @param null $time
     * @return array|bool
     */
    public function getTermsByDate($time = null)
    {
        $data = $dataTemp = [];

        if ($time === null)
        {
            return $data;
        }

        $start = date('Y', $time) * 1 - 1;

        $end = $start + 2;

        if ($this->cache_on >= 1)
        {
            for ($i = $start; $i <= $end; $i++)
            {
                $dataTemp[$i] = json_decode(Cache::get(self::CACHE_KEY . ':' . $i),true);
            }
        }

        $years = [];

        for ($i = $start; $i <= $end; $i++)
        {
            if (!isset($dataTemp[$i]) || $dataTemp[$i] === false || $dataTemp[$i] === null || empty($dataTemp[$i]))
            {
                $years[] = $i;
            }
        }

        if (!empty($years))
        {
            /**
             * 计算需要从库里获取的区间
             */
            $beginTime = strtotime($years[0] . '-01-01 0:0:0');
            $endTime = strtotime(end($years) . '-12-31 23:59:59');
//            $beginTime = date_to_unixtime($years[0] . '-01-01 0:0:0');
//            $endTime = date_to_unixtime(end($years) . '-12-31 23:59:59');
//            $beginTime = ($years[0] . '-01-01 0:0:0');
//            $endTime = (end($years) . '-12-31 23:59:59');
            try
            {
                $temp = $this->field('time,deg')
                    ->order('time', 'ASC')
//                     ->whereTime('time', 'between', [$beginTime, $endTime])
                    // 此处不能使用whereTime  支持不友好。查询不到数据
                    ->where('time between ' . $beginTime . ' and ' . $endTime)
                    ->selectOrFail();

                $temp = json_decode(json_encode($temp, true), true);
            }
            catch (\Exception $e)
            {
                $temp = [];
                \think\Log::write('请及时补充二十四节气时间表：' . $e->getMessage(), 'error', true);
            }
            if (!empty($temp))
            {
                foreach ($years as $y)
                {
                    $yearData = [];

                    foreach ($temp as $t)
                    {
                        if ($y == date('Y', $t['time']))
                        {
                            $yearData[] = $t;
                        }
                    }
                    $dataTemp[$y] = $yearData;
                    // 按年份写入缓存
                    Cache::set(self::CACHE_KEY . ':' . $y, json_encode($dataTemp[$y],true), self::CACHE_TIME);
                }
            }
        }
        /**
         * 将数据拼成正序1维数组
         */
        foreach ($dataTemp as $dt)
        {
            $data = array_merge($data, $dt);
        }

        return $data;
    }

    /**
     * 不再使用全部数据缓存
     * 获取数据库中所有的二十四节气时间 并缓存
     * 按时间正序排序
     * @return array|bool|mixed|\PDOStatement|string|\think\Model
     */
    public function getAllTerms()
    {
        $data = false;
        if ($this->cache_on >= 1)
        {
            $data = Cache::get('solar_terms');
        }

        if ($data === false)
        {
            try
            {
                $data = $this->field('time,deg')->order('time', 'ASC')->selectOrFail();

                $data = json_decode(json_encode($data, true), true);

                Cache::set('solar_terms', $data, 86400 * 30);
            }
            catch (\Exception $e)
            {
                $data = [];
                \think\Log::write('请及时补充二十四节气时间表', 'error', true);
            }
        }

        return $data;
    }
}
